package com.zlp.alipay.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alipay.api.internal.util.AlipaySignature;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zlp.alipay.dto.OrderReq;
import com.zlp.alipay.dto.RefundReq;
import com.zlp.alipay.dto.pay.AlipayBean;
import com.zlp.alipay.dto.pay.PayRefundBean;
import com.zlp.alipay.enums.PaySatusEnum;
import com.zlp.alipay.mapper.OrderMapper;
import com.zlp.alipay.model.Order;
import com.zlp.alipay.model.Pay;
import com.zlp.alipay.model.PayRefund;
import com.zlp.alipay.service.OrderService;
import com.zlp.alipay.service.PayRefundService;
import com.zlp.alipay.service.PayService;
import com.zlp.alipay.util.AliPayUtil;
import com.zlp.alipay.util.AlipayProperties;
import com.zlp.alipay.enums.OrderEnum;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * <p>
 * 订单表 服务实现类
 * </p>
 *
 * @author ZouLiPing
 * @since 2021-11-04
 */
@Service
@RequiredArgsConstructor
@Slf4j(topic = "OrderServiceImpl")
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    private final AliPayUtil aliPayUtil;
    private final AlipayProperties alipayProperties;
    private final PayService payService;
    private final PayRefundService payRefundService;

    @SneakyThrows
    @Override
    public String orderPay(OrderReq orderReq) {

        log.info("orderPay.req orderReq={}", JSON.toJSONString(orderReq));
        BigDecimal orderAmount = orderReq.getOrderAmount();
        // 1.产生订单
        Order order = new Order();
        order.setOrderSn(System.currentTimeMillis() + "");
        order.setMemberId(1L);
        order.setMemberUsername("给自己一个smile");
        order.setPayAmount(orderAmount);
        order.setPayType(orderReq.getPayType());
        order.setStatus(OrderEnum.ORDER_STATUS_NOT_PAY.getStatus());
        order.setCreateTime(DateUtil.date());
        order.setUpdateTime(DateUtil.date());
        this.save(order);

        // 2. 调用支付宝
        AlipayBean alipayBean = new AlipayBean();
        alipayBean.setOut_trade_no(order.getOrderSn());
        alipayBean.setSubject("充值:" + order.getPayAmount());
        alipayBean.setTotal_amount(orderAmount.toString());
        String pay = aliPayUtil.pay(alipayBean);
        log.info("orderPay.resp pay={}", pay);
        return pay;
    }

    @Override
    public String notifyPayResult(HttpServletRequest request) {

        log.info("notifyPayResult ===> Payment callback");
        // 1.从支付宝回调的request域中取值放到map中
        Map<String, String[]> requestParams = request.getParameterMap();
        Map<String, String> params = getReqParam(requestParams);
        //2.封装必须参数
        // 商户订单号
        String outTradeNo = params.get("out_trade_no");
        String tradeNo = params.get("trade_no");
        //交易状态
        String tradeStatus = params.get("trade_status");
        log.info("notifyPayResult.resp outTradeNo:{},tradeStatus:{}", outTradeNo, tradeStatus);

        // 3.签名验证(对支付宝返回的数据验证，确定是支付宝返回的)
        boolean signVerified = false;
        try {
            // 3.1 调用SDK验证签名
            signVerified = AlipaySignature.rsaCheckV1(params, alipayProperties.getPublicKey(), alipayProperties.getCharset(), alipayProperties.getSignType());
        } catch (Exception e) {
            e.printStackTrace();
            log.info("notifyPayResult.resp Signature verification failed:{}", e.getMessage());

        }
        Order order = this.getOrderByOrderNo(outTradeNo);
        //4.对验签进行处理
        if (!signVerified) {
            savePay(tradeNo, order, PaySatusEnum.PAY_FAIL.getStatus());
            log.info("notifyPayResult.resp ====>Signature verification failed");
            return "failure";
        }
        //只处理支付成功的订单: 修改交易表状态,支付成功
        if (StrUtil.isNotBlank(tradeStatus) &&
                ("TRADE_FINISHED".equals(tradeStatus) || "TRADE_SUCCESS".equals(tradeStatus))) {
            //根据订单号查找订单,防止多次回调的问题(幂等性)
            if (Objects.nonNull(order) && order.getStatus() == OrderEnum.ORDER_STATUS_NOT_PAY.getStatus()) {
                //修改订单状态
                order.setStatus(OrderEnum.ORDER_STATUS_PAID.getStatus());
                order.setPaymentTime(DateUtil.date());
                this.updateById(order);
                // 支付流水
                savePay(tradeNo, order, PaySatusEnum.PAY_SUCCESS.getStatus());
            }
            return "success";
        }
        savePay(tradeNo, order, PaySatusEnum.PAY_FAIL.getStatus());
        log.info("notifyPayResult.resp ====>payment failed");
        return "failure";
    }

    private void savePay(String tradeNo, Order order, Integer payStatus) {
        Pay pay = new Pay();
        pay.setOrderSn(order.getOrderSn());
        pay.setPayNo(tradeNo);
        pay.setPayType(order.getPayType());
        pay.setPayAmount(order.getPayAmount());
        pay.setPayStatus(payStatus);
        pay.setPaymentTime(new Date());
        pay.setDeleteStatus(0);
        payService.save(pay);
    }

    @Override
    public Order getOrderByOrderNo(String orderNo) {

        log.info("getOrderByOrderNo.req orderNo={}", orderNo);
        LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Order::getOrderSn, orderNo);
        queryWrapper.last(" limit 1");
        return this.getOne(queryWrapper);
    }

    @Override
    public String refund(RefundReq refundReq) {

        log.info("refund.req refundReq={}", JSON.toJSONString(refundReq));
        PayRefundBean payRefund = new PayRefundBean();
        Pay pay = payService.getByOrderNo(refundReq.getOrderNo());
        payRefund.setTrade_no(pay.getPayNo());
        payRefund.setOut_trade_no(pay.getOrderSn());
        payRefund.setRefund_reason(refundReq.getRefundReason());
        payRefund.setRefund_currency("CNY"); //人民币
        payRefund.setRefund_amount(refundReq.getRefundAmount().toString());
        String outRequestNo = payRefundService.saveRefundRecord(refundReq,pay.getPayNo());
        payRefund.setOut_request_no(outRequestNo);
        String result = aliPayUtil.payRefund(payRefund);
        log.info("payReturn.resp result={}", result);
        return result;
    }




    /**
     * 获取支付回调请求参数
     *
     * @param requestParams
     * @date: 2021/11/4 11:08
     * @return: java.util.Map<java.lang.String, java.lang.String>
     */
    private Map<String, String> getReqParam(Map<String, String[]> requestParams) {
        Map<String, String> params = new HashMap();
        for (String name : requestParams.keySet()) {
            String[] values = requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
        }
        return params;
    }
}
